﻿/*
* 模拟实现同步机构，以避免发生进程执行时可能出现的与时间有关的错误
* Yu Sitong
* YuSitong1999@qq.com
* 2019-10-02
*/

#include <iostream>
#include <vector>
#include <deque>
using namespace std;

// 语句执行的操作
enum class Operator{
	P, V, Put, GET, produce, consume, GOTO, NOP
};

// 进程运行状态
enum class Status {
	runtime, ready, waiting, finished
};

// 语句 操作和参数
struct Instruction{
	Operator opt;
	int parameter;
	Instruction(Operator opt = Operator::NOP, int parameter = 0) :opt(opt), parameter(parameter) {}
};

// 生产者程序
Instruction* PA[5] = {
	new Instruction(Operator::produce),
	new Instruction(Operator::P,1),
	new Instruction(Operator::Put),
	new Instruction(Operator::V,2),
	new Instruction(Operator::GOTO,0)
};

// 消费者程序
Instruction* SA[5] = {
	new Instruction(Operator::P,2),
	new Instruction(Operator::GET),
	new Instruction(Operator::V,1),
	new Instruction(Operator::consume),
	new Instruction(Operator::GOTO,0)
};

// 进程控制块
struct PCB {
	string name;
	Status status;
	int reason;
	int pc;
	PCB(string name = "", Status status = Status::ready, int reason = 0, int pc = 0) :
		name(name), status(status), reason(reason), pc(pc) {}
};

// 就绪进程 等待进程
vector<PCB*>ready, waiting;
// 当前行
int PC;
// 信号量
int s[3];

// 生产出字符 取出准备消费的字符
char inChar, outChar;
// 生产字符放入位置 消费字符取出自位置
int IN, out;
// 字符队列
char B[10];

// 生产者进程 消费者进程
PCB *produce, *consume;

// 进程结束
bool finished;

// 执行当前进程语句
void run(PCB* pcb)
{
	clog << "执行" << pcb->name << endl;
	int i = PC;
	
	Instruction *j;
	if (pcb->name == "produce") {
		j = PA[i];
	}
	else {
		j = SA[i];
	}

	PC = i + 1;

	switch (j->opt)
	{
	case Operator::P: {//TODO
		clog << "执行p操作" << endl;
		if (--s[j->parameter] < 0) {
			pcb->status = Status::waiting;
			pcb->reason = j->parameter;
			waiting.push_back(pcb);
			return;
		}
		break;
	}
	case Operator::V: {//TODO
		clog << "执行v操作" << endl;
		if (++s[j->parameter] >= 0) {
			//clog << "! V" << endl;
			for (vector<PCB*>::iterator it = waiting.begin(); it != waiting.end(); ++it) {
				if ((*it)->reason == j->parameter) {
					ready.push_back(*it);
					(*it)->status = Status::ready;
					waiting.erase(it);
					break;
				}
			}
		}
		break;
	}
	case Operator::GOTO: {
		clog << "执行goto" << endl;
		PC = j->parameter;
		break;
	}
	case Operator::NOP: {
		clog << "执行nop" << endl;
		break;
	}
	case Operator::Put: {
		clog << "执行put" << endl;
		B[IN] = inChar;
		IN = (IN + 1) % 10;
		break;
	}
	case Operator::GET: {
		clog << "执行get" << endl;
		outChar = B[out];
		B[out] = 0;
		out = (out + 1) % 10;
		break;
	}
	case Operator::produce: {
		clog << "执行生产" << endl;
		cout << "produce(输入不止一个字符 -> 暂不生产) : ";
		string inString;
		cin >> inString;
		if (inString.length() > 1){
			inChar = '\0';
		}
		else {
			inChar = inString[0];
		}
		break;
	}
	case Operator::consume: {
		clog << "执行消费" << endl;
		cout << "consume : " << outChar << endl;
		break;
	}
	}
	pcb->status = Status::ready;
	ready.push_back(pcb);

	if (!finished) {
		cout << "生产者运行结束？[y/n]" << endl;
		string tmp;
		cin >> tmp;
		if (tmp[0] == 'y') {
			produce->status = Status::finished;
			for (auto it = ready.begin(); it != ready.end(); ++it)
			{
				if ((*it) == produce) {
					ready.erase(it);
					break;
				}
			}
			for (auto it = waiting.begin(); it != waiting.end(); ++it)
			{
				if ((*it) == produce) {
					waiting.erase(it);
					break;
				}
			}
		}
		finished = true;
	}
}

// 就绪队列 等待队列内容
void display()
{
	cout << "ready" << endl;
	for (auto ptr : ready) {
		cout << ptr->name;
		cout << " pc " << ptr->pc;
		cout << " rea " << ptr->reason;
		cout << endl;
	}
	cout << endl;

	cout << "waiting" << endl;
	for (auto ptr : waiting) {
		cout << ptr->name;
		cout << " pc " << ptr->pc;
		cout << " rea " << ptr->reason;
		cout << endl;
	}
	cout << endl;
	cout << "s " << s[1] << " " << s[2] << endl;

	cout << "B ";
	for (auto v : B)cout << v << " ";
	cout << endl;
	cout << "inChar " << inChar << " outChar " << outChar << endl;
	cout << endl << endl;
}


int main(){
	//初始化信号量
	s[1] = 10;
	s[2] = 0;

	//初始化PCB
	produce = new PCB("produce", Status::ready, 0, 0);
	consume = new PCB("consume", Status::ready, 0, 0);
	ready.push_back(produce);
	ready.push_back(consume);

	//当前进程
	PCB* nowPcb = produce;
	PC = 0;

	//处理器调度程序
	while (true) {
		cout << "-----------------------------" << endl;

		//保护现场
		nowPcb->pc = PC;

		//有就绪进程
		if (ready.empty())break;
		
		//随机选一个就绪进程
		int id = rand() % ready.size();
		nowPcb = ready[id];
		ready.erase(ready.begin() + id);

		//运行态
		nowPcb->status = Status::runtime;

		//当前PC
		PC = nowPcb->pc;

		//执行指令
		run(nowPcb);

		display();
	}
	delete produce;
	delete consume;
	return 0;
}
